﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Gencode.VECore.VectorShape;

namespace Gencode.VECore
{
    using DrawList = List<Gencode.VECore.VectorShape.VECShape>;
    using System.Collections;

    /// <summary>
    /// List of graphic objects
    /// </summary>
    [Serializable]
    public class ShapeList : IEnumerable
    {
        private DrawList _shapeList;

        public ShapeList()
        {
            _shapeList = new DrawList();
        }

        /// <summary>
        /// Clear all objects in the list
        /// </summary>
        /// <returns>
        /// true if at least one object is deleted
        /// </returns>
        public bool Clear()
        {
            bool result = (_shapeList.Count > 0);
            _shapeList.Clear();
            return result;
        }

        /// <summary>
        /// 
        /// </summary>
        public int Count
        {
            get
            {
                return _shapeList.Count;
            }
        }

        public VECShape this[int index]
        {
            get
            {
                if (index < 0 || index >= _shapeList.Count)
                    return null;

                return _shapeList[index];
            }
        }


        /// <summary>
        /// SelectedCount and GetSelectedObject allow to read
        /// selected objects in the loop
        /// </summary>
        public int SelectionCount
        {
            get
            {
                int n = 0;

                foreach (VECShape shape in Selection)
                {
                    n++;
                }

                return n;
            }
        }


        /// <summary>
        /// Returns INumerable object which may be used for enumeration
        /// of selected objects.
        /// 
        /// Note: returning IEnumerable<VECShape> breaks CLS-compliance
        /// (assembly CLSCompliant = true is removed from AssemblyInfo.cs).
        /// To make this program CLS-compliant, replace 
        /// IEnumerable<VECShape> with IEnumerable. This requires
        /// casting to object at runtime.
        /// </summary>
        /// <value></value>
        public IEnumerable<VECShape> Selection
        {
            get
            {
                foreach (VECShape shape in _shapeList)
                {
                    if (shape.Selected)
                    {
                        yield return shape;
                    }
                }
            }
        }

        /// <summary>
        /// Inserts a VECShape on the top of the list
        /// </summary>
        /// <param name="shape"></param>
        internal void Add(VECShape shape)
        {
            _shapeList.Insert(0, shape);
        }

        /// <summary>
        /// Insert object to specified place.
        /// Used for Undo.
        /// </summary>
        internal void Insert(int index, VECShape shape)
        {
            if ( index >= 0  && index < _shapeList.Count )
            {
                _shapeList.Insert(index, shape);
            }
        }

        /// <summary>
        /// Removes a VECShape from the list
        /// </summary>
        /// <param name="shape"></param>
        internal void Remove(VECShape shape)
        {
            if (_shapeList.Contains(shape))
                _shapeList.Remove(shape);
        }

        /// <summary>
        /// Removes all selected objects
        /// </summary>
        internal void RemoveSelection()
        {
            foreach (VECShape shape in _shapeList)
            {
                if (shape.Selected)
                    _shapeList.Remove(shape);
            }
        }

        /// <summary>
        /// Replace shape in specified shape.
        /// Used for Undo.
        /// </summary>
        internal void Replace(int index, VECShape shape)
        {
            if (index >= 0 && index < _shapeList.Count)
            {
                _shapeList.RemoveAt(index);
                _shapeList.Insert(index, shape);
            }
        }

        /// <summary>
        /// Replace shape specified shape.
        /// Retruns false if failed to repalce
        /// DO NOR CALL THIS MESSAGE OUTSIDE OF THE LAYER! CALL layer.Replace(...) INSTEAD!
        /// </summary>
        internal bool Replace(VECShape originalShape, VECShape newShape)
        {
            if (_shapeList.Contains(originalShape))
            {
                int index = _shapeList.IndexOf(originalShape);
                _shapeList[index] = newShape;
                return true;
            }

            return false;
        }

        /// <summary>
        /// Remove object by index.
        /// Used for Undo.
        /// </summary>
        public void RemoveAt(int index)
        {
            _shapeList.RemoveAt(index);
        }

        /// <summary>
        /// Delete last added object from the list
        /// (used for Undo operation).
        /// </summary>
        public void DeleteLastAddedObject()
        {
            if ( _shapeList.Count > 0 )
            {
                _shapeList.RemoveAt(0);
            }
        }

        /// <summary>
        /// Selects all shapes that intersect with the rectangle
        /// </summary>
        /// <param name="rectangle"></param>
        public void SelectShapes(System.Windows.Rect rectangle)
        {
            UnselectAll();

            foreach (VECShape shape in _shapeList)
            {
                if (shape.IntersectsWith(rectangle))
                    shape.Selected = true;
            }

        }

        public void UnselectAll()
        {
            foreach (VECShape shape in _shapeList)
            {
                shape.Selected = false;
            }
        }

        public void SelectAll()
        {
            foreach (VECShape shape in _shapeList)
            {
                shape.Selected = true;
            }
        }

        ///// <summary>
        ///// Delete selected items
        ///// </summary>
        ///// <returns>
        ///// true if at least one object is deleted
        ///// </returns>
        //public bool DeleteSelection()
        //{
        //    bool result = false;

        //    int n = _shapeList.Count;

        //    for (int i = n - 1; i >= 0; i--)
        //    {
        //        if (((VECShape)_shapeList[i]).Selected)
        //        {
        //            _shapeList.RemoveAt(i);
        //            result = true;
        //        }
        //    }

        //    return result;
        //}


        /// <summary>
        /// Move selected items to front (beginning of the list)
        /// </summary>
        /// <returns>
        /// true if at least one object is moved
        /// </returns>
        public bool MoveSelectionToFront()
        {
            int n;
            int i;
            DrawList tempList;

            tempList = new DrawList();
            n = _shapeList.Count;

            // Read source list in reverse order, add every selected item
            // to temporary list and remove it from source list
            for (i = n - 1; i >= 0; i--)
            {
                if ((_shapeList[i]).Selected)
                {
                    tempList.Add(_shapeList[i]);
                    _shapeList.RemoveAt(i);
                }
            }

            // Read temporary list in direct order and insert every item
            // to the beginning of the source list
            n = tempList.Count;

            for (i = 0; i < n; i++)
            {
                _shapeList.Insert(0, tempList[i]);
            }

            return (n > 0);
        }

        /// <summary>
        /// Move selected items to back (end of the list)
        /// </summary>
        /// <returns>
        /// true if at least one object is moved
        /// </returns>
        public bool MoveSelectionToBack()
        {
            int n;
            int i;
            DrawList tempList;

            tempList = new DrawList();
            n = _shapeList.Count;

            // Read source list in reverse order, add every selected item
            // to temporary list and remove it from source list
            for (i = n - 1; i >= 0; i--)
            {
                if ((_shapeList[i]).Selected)
                {
                    tempList.Add(_shapeList[i]);
                    _shapeList.RemoveAt(i);
                }
            }

            // Read temporary list in reverse order and add every item
            // to the end of the source list
            n = tempList.Count;

            for (i = n - 1; i >= 0; i--)
            {
                _shapeList.Add(tempList[i]);
            }

            return (n > 0);
        }

        #region IEnumerable Members

        public IEnumerator GetEnumerator()
        {
            return new ShapeListEnumerator(this);
        }

        #endregion
    }

    public class ShapeListEnumerator : IEnumerator
    {
        ShapeList _list;
		int index;

        public ShapeListEnumerator(ShapeList list)
		{
			_list = list;
            index = _list.Count;
		}

		#region IEnumerator Members

        public object Current
        {
            get
            {
                return _list[index];
            }
        }

        public bool MoveNext()
        {
            if (index > 0)
            {
                index--;
                return true;
            }

            return false;
        }

        public void Reset()
        {
            index = _list.Count;
        }

		#endregion
    }
}
